#include <unistd.h>
#include <strings.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <err.h>
#include "stooge.h"

#define QUICK_SORT      0
#define STOOGE_SORT     1

void usage(char* pgname)
{
	fprintf(stdout,"Usage:\n");
	fprintf(stdout,"%s -h\n",pgname);
	fprintf(stdout,"%s -V\n",pgname);
	fprintf(stdout,"%s [options][file...]\n",pgname);

	fprintf(stdout,"Options:\n");
	fprintf(stdout,"%s -V, --version\t\t\tPrint version and quit.\n",pgname);		
	fprintf(stdout,"%s -h, --help\t\t\tPrint this information and quit.\n",pgname);

	fprintf(stdout,"%s -q, --quick\t\t\tUse the quicksort algorithm.\n",pgname);
	fprintf(stdout,"%s -s, --stooge\t\t\tUse the stoogesort algorithm.\n",pgname);

	fprintf(stdout,"Examples:\n");
 
	fprintf(stdout,"%s -q myFile.txt\n",pgname);
	fprintf(stdout,"%s -s myFile.txt\n",pgname);
	
}

int *readLine(FILE *file) {

    if (file == NULL) {
        printf("Error: file pointer is null.");
        exit(1);
    }

    int maximumLineLength = 128;
    int *lineBuffer = (int *)malloc(sizeof(int) * maximumLineLength);

    if (lineBuffer == NULL) {
        printf("Error allocating memory for line buffer.");
        exit(1);
    }

    int ch[1];
        ch[0] = 0;
    int leidos = fread(ch,1,1,file);
    int count = 0;

    while ((leidos==1) && (ch[0] != '\n')) {
        if (count == maximumLineLength) {
            maximumLineLength += 128;
            lineBuffer = realloc(lineBuffer, sizeof(int) * maximumLineLength);
            if (lineBuffer == NULL) {
                printf("Error reallocating space for line buffer.");
                exit(1);
            }
        }

        lineBuffer[count] = ch[0];
        count++;
        ch[0] = 0;
        leidos = fread(ch,1,1,file);
    }

    if(leidos==1){
        lineBuffer[count] = ch[0];
        lineBuffer = realloc(lineBuffer, sizeof(int) * (count+1));
    } else {
        // agrego \n a la ultima linea si no lo tiene para poder ordenarla
        lineBuffer[count] = '\n';
    }

    return lineBuffer;
}

int pivot_qs(int** lines, int i, int j) {

	int x, pivote;
	int *valor_pivote;
    int *aux;

	pivote = i;
	valor_pivote = lines[pivote];

	for (x=i+1; x<=j; x++) {
        if(linecmp(lines[x],valor_pivote)<0){
			pivote++;
			aux = lines[x];
			lines[x] = lines[pivote];
			lines[pivote] = aux;
		}
	}

	aux = lines[i];
	lines[i] = lines[pivote];
	lines[pivote] = aux;
	return pivote;
}

void ordenar_qs(int** lines, int i, int j) {
	int pivote;
	if (i<j) {

		pivote = pivot_qs(lines, i, j);
		ordenar_qs(lines, i, pivote-1);
		ordenar_qs(lines, pivote+1, j);
	}
}

void int2String(int* line, int last){

    int ch = line[0]; 
    int count = 0;
    while (ch != '\n') {
        ch = line[count++];
        if(ch!='\n'){
            printf("%c",ch);
        } else if(last == 0){
            printf("%c",ch);
        }   
    }
    //en caso que sea solo un \n
    if(count==0 && last==0){ 
        printf("%c",ch);    
    } 
}

int sort(int algorithm, int fdin){
    FILE *file = fdopen(fdin, "rb");
    int *line = NULL;
    int **lines = (int **)malloc(sizeof(int *));
    int count = 0;
    //leo cada linea y las indexo en "index"
    while (!feof(file)) {
        lines = (int **)realloc(lines, sizeof(int *)*(count+1));
        line = readLine(file);
        lines[count++] = line;
    }
    
    // ultima linea no ordenar, es el EOF
    if(algorithm == QUICK_SORT){
    	ordenar_qs(lines,0,count-2);
    } else {
        stoogesort(lines,0,count-2);
    }

    //libera todas las lineas
    int i;
    for(i=0;i<count;i++){
        line = (int *)lines[i];
        if(i<count-1){
            int2String(line,0);
        } else { 
            int2String(line,1); 
        }
        free(line); 
    }

    //libero el array de punteros a las lineas
    free(lines);

    //cierro el file
    fclose(file);
    
    return 1;
}

int main(int argc, char *argv[])
{
    int fdin=0;
    int ch;

	static struct option longopts[] = {
             { "version", no_argument, NULL, 'V' },
             { "help", no_argument, NULL, 'h' },
             { "quick", required_argument, NULL, 'q' },
             { "stooge", required_argument, NULL, 's' },
	         { NULL, 0, NULL, 0 }
     };

	
	int exitValue = 0;

    while ((ch = getopt_long(argc, argv, "q:s:Vh", longopts, NULL)) != -1)
	{
         switch (ch) {
			case 'q': 
				if ((fdin = open(optarg, O_RDONLY, 0)) == -1) {
					fprintf(stderr, "unable to open %s\n", optarg);
		            usage(argv[0]);
					exit(1);
                }	
				exitValue = sort(QUICK_SORT,fdin);

				break;
			case 's': 
				if ((fdin = open(optarg, O_RDONLY, 0)) == -1) {
					fprintf(stderr, "unable to open %s\n", optarg);
		            usage(argv[0]);
					exit(1);
                }
				exitValue = sort(STOOGE_SORT,fdin);
                break;
            case 'h': 
				usage(argv[0]);
            	exit(0);	
      	    	break;
			case 'V':
            	printf("%s, version 0.1\n",argv[0]);	
            	exit(0);
      	    	break;	     
            default:
				fprintf(stderr, "DEFAULT %c\n", ch);
            	usage(argv[0]);
				exit(0);
				break;
         }
	}

	return exitValue;
}
